﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using SGP;
using System.Xml.Linq;

namespace Sprite_Editor
{
    public partial class Form1 : Form
    {
        public bool looping;

        bool mousedown;
        Point mouseloc;

        Image outparticle;
        string outparticlename;

        string particlepath;
        string emitterpath;

        CSGP_Direct3D D3D;
        CSGP_TextureManager TM;
        Emitter emitter;
        DateTime previousTime;
        ParticlePreview pp;

        Color background;
        Color previewbg;

        string currentparticle;

        public Form1()
        {
            InitializeComponent();

            looping = true;
            mousedown = false;

            D3D = CSGP_Direct3D.GetInstance();
            TM = CSGP_TextureManager.GetInstance();

            D3D.Initialize(MainSplit.Panel1, false);
            TM.Initialize(D3D.Device, D3D.Sprite);

            D3D.AddRenderTarget(splitContainer2.Panel1);

            previousTime = DateTime.Now;

            particlepath = Properties.Settings.Default.ParticlePath;
            emitterpath = Properties.Settings.Default.EmitterPath;


            background = Color.FromArgb(255, 0, 0, 0);
            previewbg = Color.FromArgb(255, 0, 0, 0);

            emitter = new Emitter();

            ShapeBox.SelectedIndex = 0;
            GravBox.SelectedIndex = 1;
            LoopBox.SelectedIndex = 0;

            emitter.EmitterRotation = (float)EmitterRotBox.Value;
            emitter.AngleRange = (float)AngleBox.Value;
            emitter.FinalColor = FinalColorBox.BackColor;
            emitter.FinalRotation = (float)RotMaxBox.Value;
            emitter.FinalScale = (float)ScaleMaxBox.Value;
            emitter.InitialColor = InitialColorBox.BackColor;
            emitter.InitialRotation = (float)RotMinBox.Value;
            emitter.InitialScale = (float)ScaleMinBox.Value;
            emitter.InitialSpeedMax = (float)SpeedMaxBox.Value;
            emitter.InitialSpeedMin = (float)SpeedMinBox.Value;
            emitter.LifetimeMax = (float)LifeMaxBox.Value;
            emitter.LifetimeMin = (float)LifeMinBox.Value;
            emitter.OffsetX = (float)WidthBox.Value / 2;
            emitter.OffsetY = (float)HeightBox.Value / 2;
            emitter.PosX = (float)MainSplit.Panel1.Width / 2;
            emitter.PosY = (float)MainSplit.Panel1.Height / 2;
            emitter.SpawnRate = (float)SpawnBox.Value;

            pp = new ParticlePreview(emitter);
            pp.PosX = (float)splitContainer2.Panel1.Width / 2;
            pp.PosY = (float)splitContainer2.Panel1.Height / 2;

            //emitter.createparticles((int)ParticleBox.Value);
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            looping = false;
        }

        public new void Update()
        {
            System.DateTime dt = System.DateTime.Now;
            TimeSpan ts = dt - previousTime;
            previousTime = dt;

            float deltaTime = (float)ts.TotalSeconds;

            if (deltaTime > .1f)
                deltaTime = .1f;

            emitter.Update(deltaTime);
            pp.Update(deltaTime);
        }

        public void Render()
        {
            D3D.Clear(MainSplit.Panel1, background);
            D3D.DeviceBegin();
            D3D.SpriteBegin();

            emitter.Render();

            D3D.SpriteEnd();
            D3D.DeviceEnd();

            D3D.Present();



            D3D.Clear(splitContainer2.Panel1, previewbg);
            D3D.DeviceBegin();
            D3D.SpriteBegin();

            if (TextureInfo.ID != -1)
                pp.Render();

            D3D.SpriteEnd();
            D3D.DeviceEnd();

            D3D.Present();
        }

        private void ShapeBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (ShapeBox.SelectedIndex)
            {
                case 0:
                    emitter.Shape = EmitterShape.Line;
                    break;
                case 1:
                    emitter.Shape = EmitterShape.Square;
                    break;
                case 2:
                    emitter.Shape = EmitterShape.Circle;
                    break;
            }
        }

        private void GravBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (GravBox.SelectedIndex)
            {
                case 0:
                    emitter.HasGravity = true;
                    break;
                case 1:
                    emitter.HasGravity = false;
                    break;
            }
        }

        private void EmitterRotBox_ValueChanged(object sender, EventArgs e)
        {
            emitter.EmitterRotation = (float)EmitterRotBox.Value;
        }

        private void WidthBox_ValueChanged(object sender, EventArgs e)
        {
            emitter.OffsetX = (float)WidthBox.Value / 2;
        }

        private void HeightBox_ValueChanged(object sender, EventArgs e)
        {
            emitter.OffsetY = (float)HeightBox.Value / 2;
        }

        private void LoopBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (LoopBox.SelectedIndex)
            {
                case 0:
                    emitter.Looping = true;
                    break;
                case 1:
                    emitter.Looping = false;
                    emitter.RemainingParticles = emitter.MaxParticles;
                    break;
            }
        }

        private void ParticleBox_ValueChanged(object sender, EventArgs e)
        {
            emitter.createparticles((int)ParticleBox.Value);
        }

        private void LifeMinBox_ValueChanged(object sender, EventArgs e)
        {
            emitter.LifetimeMin = (float)LifeMinBox.Value;
        }

        private void LifeMaxBox_ValueChanged(object sender, EventArgs e)
        {
            emitter.LifetimeMax = (float)LifeMaxBox.Value;
        }

        private void ScaleMinBox_ValueChanged(object sender, EventArgs e)
        {
            emitter.InitialScale = (float)ScaleMinBox.Value;
        }

        private void ScaleMaxBox_ValueChanged(object sender, EventArgs e)
        {
            emitter.FinalScale = (float)ScaleMaxBox.Value;
        }

        private void AngleBox_ValueChanged(object sender, EventArgs e)
        {
            emitter.AngleRange = (float)AngleBox.Value;
        }

        private void InitialColorBox_BackColorChanged(object sender, EventArgs e)
        {
            emitter.InitialColor = InitialColorBox.BackColor;
        }

        private void FinalColorBox_BackColorChanged(object sender, EventArgs e)
        {
            emitter.FinalColor = FinalColorBox.BackColor;
        }

        private void SpeedMinBox_ValueChanged(object sender, EventArgs e)
        {
            emitter.InitialSpeedMin = (float)SpeedMinBox.Value;
        }

        private void SpeedMaxBox_ValueChanged(object sender, EventArgs e)
        {
            emitter.InitialSpeedMax = (float)SpeedMaxBox.Value;
        }

        private void RotMinBox_ValueChanged(object sender, EventArgs e)
        {
            emitter.InitialRotation = (float)RotMinBox.Value;
        }

        private void RotMaxBox_ValueChanged(object sender, EventArgs e)
        {
            emitter.FinalRotation = (float)RotMaxBox.Value;
        }

        private void SpawnBox_ValueChanged(object sender, EventArgs e)
        {
            emitter.SpawnRate = (float)SpawnBox.Value;
        }

        private void MainSplit_Panel1_MouseDown(object sender, MouseEventArgs e)
        {
            mousedown = true;
            mouseloc = Cursor.Position;
        }

        private void MainSplit_Panel1_MouseUp(object sender, MouseEventArgs e)
        {
            mousedown = false;
        }

        private void MainSplit_Panel1_MouseLeave(object sender, EventArgs e)
        {
            mousedown = false;
        }

        private void MainSplit_Panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (mousedown)
            {
                emitter.PosX += Cursor.Position.X - mouseloc.X;
                emitter.PosY += Cursor.Position.Y - mouseloc.Y;
                mouseloc.X = Cursor.Position.X;
                mouseloc.Y = Cursor.Position.Y;
            }
        }

        private void InitialColorBox_MouseClick(object sender, MouseEventArgs e)
        {
            ColorDialog colorselect = new ColorDialog();

            if (DialogResult.OK == colorselect.ShowDialog())
            {
                InitialColorBox.BackColor = colorselect.Color;
            }
        }

        private void FinalColorBox_MouseClick(object sender, MouseEventArgs e)
        {
            ColorDialog colorselect = new ColorDialog();

            if (DialogResult.OK == colorselect.ShowDialog())
            {
                FinalColorBox.BackColor = colorselect.Color;
            }
        }

        private void backgroundColorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ColorDialog colorselect = new ColorDialog();

            if (DialogResult.OK == colorselect.ShowDialog())
            {
                background = colorselect.Color;
            }
        }

        private void loadImageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog load = new OpenFileDialog();
            load.InitialDirectory = particlepath;

            if (DialogResult.OK == load.ShowDialog())
            {
                TextureInfo.ID = TM.LoadTexture(load.FileName);

                TextureInfo.Width = TM.GetTextureWidth(TextureInfo.ID);
                TextureInfo.Height = TM.GetTextureHeight(TextureInfo.ID);

                currentparticle = load.FileName;

                outparticle = Image.FromFile(load.FileName);
                outparticlename = Path.GetFileName(currentparticle);

                emitter.createparticles((int)ParticleBox.Value);
                pp.Initialize();

                Properties.Settings.Default.ParticlePath = Path.GetDirectoryName(load.FileName) + @"\";
                Properties.Settings.Default.Save();

                particlepath = Properties.Settings.Default.ParticlePath;
            }
        }

        private void previewBackgroundToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ColorDialog colorselect = new ColorDialog();

            if (DialogResult.OK == colorselect.ShowDialog())
            {
                previewbg = colorselect.Color;
            }
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog OpenXml = new OpenFileDialog();
            OpenXml.Filter = "All Files|*.*|Xml Files|*.xml";
            OpenXml.FilterIndex = 2;
            OpenXml.DefaultExt = "xml";
            OpenXml.InitialDirectory = emitterpath;

            if (DialogResult.OK == OpenXml.ShowDialog())
            {
                Properties.Settings.Default.EmitterPath = Path.GetDirectoryName(OpenXml.FileName) + @"\";
                Properties.Settings.Default.Save();

                emitterpath = Properties.Settings.Default.EmitterPath;

                XDocument doc = XDocument.Load(OpenXml.FileName);

                XElement root = doc.Root;
                XElement image = root.Element("image");
                currentparticle = Path.GetDirectoryName(OpenXml.FileName);
                currentparticle += image.Value;
                XElement maxparticles = root.Element("maxparticles");
                XAttribute particles = maxparticles.Attribute("particles");
                ParticleBox.Value = Convert.ToDecimal(particles.Value);
                XElement shape = root.Element("shape");
                if (shape.Value == "Line")
                    ShapeBox.SelectedIndex = 0;
                else if (shape.Value == "Square")
                    ShapeBox.SelectedIndex = 1;
                else
                    ShapeBox.SelectedIndex = 2;
                XElement speed = root.Element("speed");
                XAttribute min = speed.Attribute("min");
                XAttribute max = speed.Attribute("max");
                SpeedMinBox.Value = Convert.ToDecimal(min.Value);
                SpeedMaxBox.Value = Convert.ToDecimal(max.Value);
                XElement lifetime = root.Element("lifetime");
                min = lifetime.Attribute("min");
                max = lifetime.Attribute("max");
                LifeMinBox.Value = Convert.ToDecimal(min.Value);
                LifeMaxBox.Value = Convert.ToDecimal(max.Value);
                XElement offset = root.Element("offset");
                XAttribute x = offset.Attribute("x");
                XAttribute y = offset.Attribute("y");
                WidthBox.Value = Convert.ToDecimal(x.Value) * 2;
                HeightBox.Value = Convert.ToDecimal(y.Value) * 2;
                XElement startcolor = root.Element("startcolor");
                XAttribute a = startcolor.Attribute("a");
                XAttribute r = startcolor.Attribute("r");
                XAttribute g = startcolor.Attribute("g");
                XAttribute b = startcolor.Attribute("b");
                InitialColorBox.BackColor = Color.FromArgb(Convert.ToInt32(a.Value), Convert.ToInt32(r.Value), Convert.ToInt32(g.Value), Convert.ToInt32(b.Value));
                XElement endcolor = root.Element("endcolor");
                a = endcolor.Attribute("a");
                r = endcolor.Attribute("r");
                g = endcolor.Attribute("g");
                b = endcolor.Attribute("b");
                FinalColorBox.BackColor = Color.FromArgb(Convert.ToInt32(a.Value), Convert.ToInt32(r.Value), Convert.ToInt32(g.Value), Convert.ToInt32(b.Value));
                XElement scale = root.Element("scale");
                XAttribute initial = scale.Attribute("initial");
                XAttribute final = scale.Attribute("final");
                ScaleMinBox.Value = Convert.ToDecimal(initial.Value);
                ScaleMaxBox.Value = Convert.ToDecimal(final.Value);
                XElement rotation = root.Element("rotation");
                XAttribute start = rotation.Attribute("start");
                XAttribute end = rotation.Attribute("end");
                RotMinBox.Value = Convert.ToDecimal(start.Value);
                RotMaxBox.Value = Convert.ToDecimal(end.Value);
                XElement anglerange = root.Element("anglerange");
                XAttribute range = anglerange.Attribute("range");
                AngleBox.Value = Convert.ToDecimal(range.Value);
                XElement emitterrotation = root.Element("emitterrotation");
                XAttribute angle = emitterrotation.Attribute("angle");
                EmitterRotBox.Value = Convert.ToDecimal(angle.Value);
                XElement gravity = root.Element("gravity");
                XAttribute hasgravity = gravity.Attribute("hasgravity");
                if (hasgravity.Value == "true")
                    GravBox.SelectedIndex = 0;
                else
                    GravBox.SelectedIndex = 1;
                XElement looping = root.Element("looping");
                XAttribute doesloop = looping.Attribute("doesloop");
                if (doesloop.Value == "true")
                    LoopBox.SelectedIndex = 0;
                else
                    LoopBox.SelectedIndex = 1;
                XElement spawnrate = root.Element("spawnrate");
                XAttribute timer = spawnrate.Attribute("timer");
                SpawnBox.Value = Convert.ToDecimal(timer.Value);

                TextureInfo.ID = TM.LoadTexture(currentparticle);
                TextureInfo.Width = TM.GetTextureWidth(TextureInfo.ID);
                TextureInfo.Height = TM.GetTextureHeight(TextureInfo.ID);

                emitter.createparticles((int)ParticleBox.Value);
            }
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog SaveXml = new SaveFileDialog();
            SaveXml.Filter = "All Files|*.*|Xml Files|*.xml";
            SaveXml.FilterIndex = 2;
            SaveXml.DefaultExt = "xml";
            SaveXml.InitialDirectory = emitterpath;

            if (DialogResult.OK == SaveXml.ShowDialog())
            {
                Properties.Settings.Default.EmitterPath = Path.GetDirectoryName(SaveXml.FileName) + @"\";
                Properties.Settings.Default.Save();

                emitterpath = Properties.Settings.Default.EmitterPath;

                string outparticlepath = Path.GetDirectoryName(SaveXml.FileName);
                outparticlepath += outparticlename;

                try
                {
                    outparticle.Save(outparticlepath);
                }
                catch (Exception)
                {
                }

                XDocument doc = new XDocument();

                XElement root = new XElement("emitter",
                    new XElement("image", Path.GetFileName(currentparticle)),
                    new XElement("maxparticles", new XAttribute("particles", emitter.MaxParticles)),
                    new XElement("shape", emitter.Shape.ToString()),
                    new XElement("speed", new XAttribute("min", emitter.InitialSpeedMin), new XAttribute("max", emitter.InitialSpeedMax)),
                    new XElement("lifetime", new XAttribute("min", emitter.LifetimeMin), new XAttribute("max", emitter.LifetimeMax)),
                    new XElement("offset", new XAttribute("x", emitter.OffsetX), new XAttribute("y", emitter.OffsetY)),
                    new XElement("startcolor", new XAttribute("a", emitter.InitialColor.A), new XAttribute("r", emitter.InitialColor.R), new XAttribute("g", emitter.InitialColor.G), new XAttribute("b", emitter.InitialColor.B)),
                    new XElement("endcolor", new XAttribute("a", emitter.FinalColor.A), new XAttribute("r", emitter.FinalColor.R), new XAttribute("g", emitter.FinalColor.G), new XAttribute("b", emitter.FinalColor.B)),
                    new XElement("scale", new XAttribute("initial", emitter.InitialScale), new XAttribute("final", emitter.FinalScale)),
                    new XElement("rotation", new XAttribute("start", emitter.InitialRotation), new XAttribute("end", emitter.FinalRotation)),
                    new XElement("anglerange", new XAttribute("range", emitter.AngleRange)),
                    new XElement("emitterrotation", new XAttribute("angle", emitter.EmitterRotation)),
                    new XElement("gravity", new XAttribute("hasgravity", emitter.HasGravity)),
                    new XElement("looping", new XAttribute("doesloop", emitter.Looping)),
                    new XElement("spawnrate", new XAttribute("timer", emitter.SpawnRate)));


                doc.Add(root);
                doc.Save(SaveXml.FileName);
            }

        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}
